<?php

declare(strict_types=1);

namespace App\Middleware;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\Utils\Context;
use Service\MessageService\WebApiRequestLogService;
use Service\UserService\UserAuthLoginService;
use Service\MemberService\MemberService;
use Service\UserService\MnUserService;

/**
 * TO C/B 小程序中间介
 * @author chenshubo
 */
class WebApiMiddleware implements MiddlewareInterface
{
    //需要排除登录控制器
    protected $except = [
        '/webapi/v1/login',//登录控制器
        '/webapi/common/graph',//图形控制器
        '/webapi/common/sms',//微信控制器
        '/webapi/common/upload',//上传文件资源
        '/webapi/common/pushgoods',//上传文件资源
        '/webapi/v1/decorate',//装修数据
        '/webapi/common/pushgoods',//调试
    ];
    
    /**
     * 需要直接返回响应的控制器
     * 无须二次处理
     */
    protected $except_response_handle_direct = [
        '/webapi/common/graph'
    ];
    
    /**
     * @var ContainerInterface
     */
    protected $container;
    
    /**
     * @var RequestInterface
     */
    protected $request;
    
    /**
     * @var HttpResponse
     */
    protected $response;
    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    /**
     * 处理中间介流程
     * {@inheritDoc}
     * @see \Psr\Http\Server\MiddlewareInterface::process($request, $handler)
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $rt_start = microtime(true);
        $param = $this->request->all();
        $token = $this->request->header('token');
        $url   = (string)$this->request->getUri();
        $parsedUrl = parse_url($url);
        $modules = \explode("/",$parsedUrl['path']);
        array_pop($modules);

        $except_url = \implode("/", $modules);
        $except_url = strtolower($except_url);
        $debug_user_mid = (int)env('APP_DEBUG_MID');
        if( $debug_user_mid ) 
        {
            $mid = $debug_user_mid;
            //会员基础信息表
            $member = MemberService::instance()->getMemberByMid($mid);
            //会员扩展信息表
            $memberinfo = MemberService::instance()->getMemberInfoByMid($mid);
            //店铺信息
            $mn_sid = $member['mn_sid'];
            $mnuser = MnUserService::instance()->getMnUserInfoByMnSid($mn_sid);
            $cid    = $member['cid'];
            
            //处理基础信息
            $client = env('APP_DEBUG_CLIENT');
            $mnid   = (int)env('APP_DEBUG_MNID');
            
            $request = $request->withAttribute('mid',(int)$mid);
            $request = $request->withAttribute('cid',(int)$cid);
            $request = $request->withAttribute('mn_sid',(int)$mn_sid);
            $request = $request->withAttribute('mnid',(int)$mnid);
            $request = $request->withAttribute('client',(string)$client);
            $request = $request->withAttribute('member',$member);
            $request = $request->withAttribute('memberinfo',$memberinfo);
            $request = $request->withAttribute('mnuser',$mnuser);
        }
        else 
        {
            //排除不需要登录的情况
            if( !in_array($except_url,$this->except) && empty($token) ) {
                return $this->response->json([
                    'status'    => 0,
                    'msg'       => 'token参数缺失'
                ]);
            }
            
            //有token的情况下
            if( !empty($token) )
            {
                $user = UserAuthLoginService::instance()->getLoginByToken($token);
                if( !in_array($except_url,$this->except) && empty($user))
                {
                    return $this->response->json([
                        'status'    => 201,
                        'msg'       => '登录已过期'
                    ]);
                }
            
                if( !empty($user) )
                {
                    //处理基础信息
                    $mid    = $user['mid'];
                    $mn_sid = $user['mn_sid'];
                    $mnid   = $user['mnid'];
                    $client = $user['client'];
                    $cid    = $user['cid'];
            
                    //判断店铺是否发生切换变更
                    //如果toC 小程序
                    if( $mnid == TO_C_MNID_TYPE && $mn_sid != $this->request->input('mn_sid') )
                    {
                        //切换店铺之后，强制删除旧店铺登录信息
                        UserAuthLoginService::instance()->removeUserLogin($token);
                        return $this->response->json([
                            'status'    => 202,
                            'msg'       => '当前店铺发生切换，请重新登录',
                        ]);
                    }
            
                    //TOB 小程序发生切换
                    if( $mnid == TO_B_MNID_TYPE && $cid != $this->request->input('cid') )
                    {
                        UserAuthLoginService::instance()->removeUserLogin($token);
                        return $this->response->json([
                            'status'    => 203,
                            'msg'       => '当前小程序发生切换，请重新登录',
                        ]);
                    }
            
                    //会员基础信息表
                    $member = MemberService::instance()->getMemberByMid($mid);
                    //会员扩展信息表
                    $memberinfo = MemberService::instance()->getMemberInfoByMid($mid);
                    //店铺信息
                    $mnuser = MnUserService::instance()->getMnUserInfoByMnSid($mn_sid);
            
                    $request = $request->withAttribute('mid',(int)$mid);
                    $request = $request->withAttribute('cid',(int)$cid);
                    $request = $request->withAttribute('mn_sid',(int)$mn_sid);
                    $request = $request->withAttribute('mnid',(int)$mnid);
                    $request = $request->withAttribute('client',(string)$client);
                    $request = $request->withAttribute('member',$member);
                    $request = $request->withAttribute('memberinfo',$memberinfo);
                    $request = $request->withAttribute('mnuser',$mnuser);
                }
            }
        }
        
        
        
        
        ///这里是设置请求属性，根据具体业务而定
        Context::set(RequestInterface::class, $request);
        
        //排除需要二次处理response的情况
        if( in_array($except_url,$this->except_response_handle_direct) ) {
            return $handler->handle($request);
        }
        
        $response = $handler->handle($request);
        $json     = $response->getBody()->getContents();
        $data     = json_decode($json,true);
        $response_data = [
            'status'    => $data['code'] ?? 0,
            'msg'       => $data['msg'] ?? '处理失败',
            'data'      => $data['data'] ?? [],
        ];        
        
        //接口tps 处理耗时
        $request_used_time = bcsub((string)microtime(true),(string)$rt_start,3);
        
        //body
        $body = $this->request->getParsedBody();
        $logs = [
            'request_terminal'      => 1,
            'request_url_hash'      => md5($url),
            'request_url'           => $url,
            'request_method'        => $this->request->getMethod(),
            'request_parameters'    => json_encode($body,JSON_UNESCAPED_UNICODE),
            'request_used_time'     => $request_used_time,
            'request_ip'            => getIp(),
            'response_code'         => $response_data['status'],
            'response_msg'          => $response_data['msg'],
            'response_contents'     => json_encode($response_data,JSON_UNESCAPED_UNICODE),
            'request_time'          => time(),
        ];
        //发布日志队列
        WebApiRequestLogService::instance()->publishMsg($logs);
        return $this->response->json($response_data);
    }
}